// 工具
export const isVoid = (val) => {
  return val === undefined
}

/**
 * @author nvp
 * @description 是否为数组
 * @date 2021-03-15 18:39:47
 * @param {any} val 判断的值
 * @return {boolean} true 为数组， false 不是数组
*/
export const isArray = (val) => {
  return Object.prototype.toString.call(val) === '[object Array]'
}

/**
 * @author nvp
 * @description 判读数组的值是否全部都是对象
 * @date 2021-03-15 18:39:47
 * @param {array} arrays 判断的值
 * @return {boolean} 
*/
export const isObjArray = (arrays) => {
  const result = isArray(arrays)

  if (result) {
    for (let i = 0, len = arrays.length; i < len; i++) {
      if (!isObject(arrays[i])) return false
    }
    return true
  } else {
    return false
  }
}

// 是否为字符串
export const isString = (str) => typeof str === 'string'

// 是否为数字
export const isNumber = (str) => typeof str === 'number'

/**
 * @author nvp
 * @description 判断是否为对象
 * @date 2021-03-15 18:39:47
 * @param {any} obj 判断的值
 * @return {boolean} true 为对象， false 不是对象
*/
export const isObject = (obj) => {
  return Object.prototype.toString.call(obj) === '[object Object]'
}

// 对象深拷贝(有很大的局限性，谨慎使用)
// 空属性不会复制

/**
 * @author nvp
 * @description 对象的深拷贝函数（使用的是json转换的方式，有一定局限性）
 * @date 2021-03-13 10:28:38
 * @param {object} obj 需要拷贝的对象
 * @return {object} 拷贝出来的新对象
*/
export const copy = (obj) => {
  return JSON.parse(JSON.stringify(obj))
}

/**
 * @author nvp
 * @description 将obj中的key对应的值赋值给item,并且这个key必须是item中原本就存在的
 * @date 2021-03-15 18:36:48
 * @param {object} item 接收值的对象
 * @param {object} ...obj 传递值的对象
 * @return {object} item 传入的对象
*/
export const fillIn = (item, ...obj) => {
  if (!isObject(item)) return item
  const len = obj.length

  for (let i = 0; i < len; i++) {
    const objs = obj[i]

    // obj 中不是对象则直接跳过
    if (isObject(objs)) {
      for (const key in item) {
        const val = item[key]
  
        item[key] = isVoid(objs[key]) ? val : objs[key]
      }
    }
  }
  return item
}

/*
  对象取值，值的位置类似 selectVal.datum
  从对象obj中获取 selectVal.datum 位置的值
  obj：取值的对象
  valString: 值的位置，例selectVal.datum
*/
export const getContinuousVals = (obj, valString) => {
  const keys = valString.split('.')
  let values = obj

  keys.forEach(key => {
    values = values[key]
  })
  return values
}

/*
  数组匹配
  param:
    arrayVal & arrayExa = （数组）
    arrayVal 中是否有值与 arrayExa 中的值相等

  return Boolean
*/
/**
 * @author nvp
 * @description 数组匹配
 * @date 2021-03-15 18:51:53
 * @param {array} arrayVal 任意数组
 * @param {array} arrayExa 任意数组
 * @return {boolean} 
*/
export const intSome = (arrayVal, arrayExa) => {
  if (!isArray(arrayVal) || !isArray(arrayExa)) return
  return arrayVal.some(value => arrayExa.some(val => val === value))
}

/*
  列表数组去重
  attrs: 用于确认数组项唯一性key
*/
export const unique = (array, attrs = 'id') => {
  const r = []

  for (let i = 0, l = array.length; i < l; i++) {
    for (let j = i + 1; j < l; j++) {
      if (array[i][attrs] === array[j][attrs]) j = ++i
    }
    r.push(array[i])
  }

  return r
}

/*
  对象格式转换 将 dataArray
  [{
    text: '工时单',
    val: '1'
  }]
  格式的数据 转换成 obj
  {
    '1': '工时单'
  }
*/
export const objFormatSwitch = (obj, dataArray, option = {}) => {
  const valKey = option.valKey || 'val'
  const textKey = option.textKey || 'text'

  for (let i = 0, len = dataArray.length; i < len; i++) {
    const item = dataArray[i]

    obj[item[valKey]] = item[textKey]
  }

  return obj
}

// 创建一个数组的快速索引对象 { id: index } 的格式(确保key的值是唯一的)
export const createFastIndexObj = (array, key = 'id') => {
  const indexObj = {}

  array.forEach((item, index) => {
    indexObj[item[key]] = index
  })

  return indexObj
}

// 计算对象内某数值字段值的总和
export const objReduce = (list, countKey) => {
  const sumArray = list.map(item => parseFloat(item[countKey]) || 0)
  let totals = 0

  if (sumArray.length !== 0) {
    totals = sumArray.reduce((total, value) => total + value)
  }

  return totals
}

// 获取列表中 对应字段(key) 为val的项
export const getListObjet = (list, key, val) => {
  for (let len = list.length, i = 0; len > i; i++) {
    if (list[i][key] === val) {
      return list[i]
    }
  }
}

// 复制文本
export const copyText = (text, callback) => {
  var tag = document.createElement('input')

  tag.setAttribute('id', 'cp_hgz_input')
  tag.value = text
  document.getElementsByTagName('body')[0].appendChild(tag)
  document.getElementById('cp_hgz_input').select()
  document.execCommand('copy')
  document.getElementById('cp_hgz_input').remove()
  if (callback) { callback(text) }
}

/**
 * 空函数，一般用来占位
 * @returns {null}
*/
export const empty = _ => null

// 通过key获取对应列表的对应值的项

export const getListItem = (list, keys, val) => {
  const len = list.length

  for (let i = 0; i < len ; i++) {
    if (list[i][keys] == val) {
      return list[i]
    }
  }
}
/**
 * 将手机格式转化为 185****1245格式
 * @name telPhoneFormatter
 * @param {string|number} phone 手机号
 * @return {string}
 * */ 
export const telPhoneFormatter = (phone) => {
  const len = phone.length

  if (isNumber(phone)) phone = phone.toString()
  // phone不是字符串或者字符长度小于7时直接返回
  if (!isString(phone) || len <= 7) return phone

  const maxHideLen = phone.length - 4 //最大的隐藏长度

  return phone.split('').map((char, index) => (index >= 3 && index < maxHideLen) ? '*' : char).join('')
}

// antiShaking状态的枚举
const antiShakingStateEnum = {
  ACTIVE: 'active',
  STIFF: 'stiff'
}
/**
 * 函数防抖
 * 在调用一次fn之后需要在 space 时间内没有再次进行调用时，才会在下次调用时执行fn
 * 函数本身有两个状态 活跃(active)和非活跃的(Stiff)
 * 开始为active状体，当fn触发后，状态转为Stiff，并进行计时，计时到期后状态转变为active
 * 状态转为Stiff，计时未到期时调用fn，则重新计时
 * @param {function} fn 要进行防抖的函数
 * @param {number} space 防抖的时间间隔
 * @return {fn} 封装好的防抖函数
 * */
export const antiShaking = (fn, space) => {
  fn._state = antiShakingStateEnum.ACTIVE
  fn._is = null // 保存计时器回调

  return () => {
    if (fn._state === antiShakingStateEnum.ACTIVE) {
      fn()
      fn._state = antiShakingStateEnum.STIFF
    } else {
      clearTimeout(fn._is)
      fn._is = setTimeout(() => {
        fn._state = antiShakingStateEnum.ACTIVE
      }, space)
    }
  }
}
